#include <fstream>
#include <iostream>

#include "../Lzma86/LzmaLib.h";
#pragma comment (lib, "../release/Lzma86.lib")

#include "lzma-helper.h"

using namespace std;

/*
class LzmaHelper
{
public:
	// compress from file to file
	static bool CompressFile(const string& source, const string& dest);

	// decompress from memory to file
	static bool DecompressMemory(const unsigned char* source, int length, const string& dest);
};
*/

bool LzmaHelper::CompressFile(const string& source, const string& dest)
{
	ifstream fs(source, ios::binary);
	ofstream os(dest, ios::binary);

	if(fs.bad() || os.bad())
	{
		cout << "source or dest maybe bad." << endl;
		return false;
	}

	// get length of file:
	fs.seekg (0, ios::end);
	int length = fs.tellg();
	fs.seekg (0, ios::beg);

	// allocate memory:
	unsigned char* buffer = new unsigned char [length];

	// read data as a block:
	fs.read ((char*)buffer, length);
	fs.close();

	//cout.write (buffer,length);

	int output_length = length + 200000;
	unsigned char* output_buffer = new unsigned char[output_length];
	
	unsigned char option[5]; // = {0x5d, 0, 0, 1, 0};
	int option_length = 5;

	int hr = LzmaCompress(output_buffer, (size_t*)&output_length, buffer, length, option, (size_t*)&option_length,
		4,
		(1 << 16),
		3,
		0,
		2,
		32,
		1);

	if(hr != SZ_OK)
	{
		cout << "Compression failed. ERROR=" << hr << endl;
		return false;
	}

	cout << "option->";
	for(int i=0; i<5; i++)
		cout << hex << (short)option[i] << " ";
	cout << dec << endl;
	cout << "good" << endl;


	os.write((const char*)output_buffer, output_length);
	os.close();
	cout << "dest file created." << endl;

	// test
	{
		int original_length = output_length + 200000;
		unsigned char* original_buffer = new unsigned char[original_length];

		int hr = LzmaUncompress(original_buffer, (size_t*)&original_length, output_buffer, (size_t*)&output_length, option, 5);
		if(hr != SZ_OK && hr != SZ_ERROR_INPUT_EOF) // lzma bug -- return INPUT_EOF means OK!!
		{
			cout << "Decommpression test failed. ERROR=" << hr << endl;
			return false;
		}
	}


	delete[] buffer;
	delete[] output_buffer;

	return true;
}

bool LzmaHelper::DecompressMemory(const unsigned char* source, int length, const wchar_t* dest)
{
	ofstream os(dest, ios::binary);
	if(os.bad())
	{
		cout << "dest maybe bad." << endl;
		return false;
	}

	unsigned char option[5] = {0x5d, 0, 0, 1, 0};

	int output_length = length + 200000;
	unsigned char* output_buffer = new unsigned char[output_length];

	int hr = LzmaUncompress(output_buffer, (size_t*)&output_length, source, (size_t*)&length, option, 5);
	if(hr != SZ_OK && hr != SZ_ERROR_INPUT_EOF) // lzma bug -- return INPUT_EOF means OK!!
	{
		cout << "Decommpression failed. ERROR=" << hr << endl;
		return false;
	}

	os.write((const char*)output_buffer, output_length);
	os.close();
	cout << "dest file created." << endl;

	delete[] output_buffer;

	return true;
}
